﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Reflection;
using Un4seen.Bass;
using sdd.subsystems.audio;
using sdd.subsystems.io;
using sdd.subsystems.display;
using sdd.subsystems.ui;
using sdd.subsystems.ui.screens;
using sdd.subsystems.config;
using sdd.apps;
using System.Threading;

// SDD# - Software Defined Devices in C# for Linux and Windows
// Director represents our Software Defined Device
// (c) 2014-2015 Chris Burri. MIT License applies. 
// See http://niston.wordpress.com

namespace sdd
{
    public class Director
    {

        #region Member Vars
        
        // device serial port
        private SerialIOComPort _SerialPort;

        // physical display driver object (internal reference)
        private IDisplay _physicalDisplay;

        // proxied display driver object (given to subsystems and apps)
        private DisplayProxy _proxiedDisplay;

        // application manager loads our apps
        private ApplicationManager _AppManager;


        private ScrMenu _SystemMenuScreen;
        private MenuItem _SystemMenu;
        private MenuItem _SysInfoMenu;

        private IntMenuItem optLcdBrightness;
        private IntMenuItem optLcdContrast;
        private IntMenuItem optBacklightBrightness;

        

        #endregion

        

        #region Constructor/Destructor
        public Director()
        {
            Console.WriteLine("Director: Starting up...");
            

            // DEBUG: determine serial port
            if (IsRunningOnMono)
            {
                _SerialPort = new SerialIOComPort("/dev/ttyUSB0");
            }
            else
            {
                _SerialPort = new SerialIOComPort("COM8");
            }
            _SerialPort.Open();

            // create serial display object and clear LEDs
            _physicalDisplay = new DisplayMxoGlk(_SerialPort);
            _proxiedDisplay = new DisplayProxy(_physicalDisplay);
            _proxiedDisplay.KeypadPreviewEvent += _proxiedDisplay_KeypadPreviewEvent;
            Display = _proxiedDisplay;
            Display.SetLedIndicators(LedLocations.Top, LedColors.Dark, true);
            Display.SetLedIndicators(LedLocations.Middle, LedColors.Dark, true);
            Display.SetLedIndicators(LedLocations.Bottom, LedColors.Dark, true);
            Display.ClearScreen();
            //Display.SetCursorPosition(1, 1);
            //Display.WriteText("Niston Cloud's SDD# Core Version " + Assembly.GetExecutingAssembly().GetName().Version.ToString());
            //Display.SetCursorPosition(1, 2);
            //Display.WriteText("Director initializing; please stand by...");
            

            // create screen manager and menu system
            ScreenManager = new ScreenManager(this, Display);

            // SYSTEM menu
            _SystemMenu = new MenuItem("sdd.sysmenu", "SDD# System Menu");            
            _SystemMenuScreen = new ScrMenu("sdd.scr.sysmenu", _SystemMenu.Caption, _SystemMenu);
            _SystemMenuScreen.AppKeyPress += _SystemMenuScreen_AppKeyPress;

            // System Info sub menu
            _SysInfoMenu = new MenuItem("sdd.sysmenu.systeminfo", "System Information");
            _SysInfoMenu.SubItems.Add(new GenericMenuItem<string>("sdd.sysmenu.systeminfo.sddcore_version", "SDD# Core Version", Assembly.GetExecutingAssembly().GetName().Version.ToString()));
            _SysInfoMenu.SubItems.Add(new GenericMenuItem<string>("sdd.sysmenu.systeminfo.os_version", "OS Version", Environment.OSVersion.ToString()));
            
            // LCD Display Settings



            // register menus
            ScreenManager.Menus.Register(_SystemMenu);
            ScreenManager.Menus.Register(_SysInfoMenu, _SystemMenu);

            // create application manager
            _AppManager = new ApplicationManager(this);

            
            // register screens
            ScreenManager.Register(new ScrNetworkSetup());            
            ScreenManager.Register(_SystemMenuScreen);

            // start internet availability tester with default values
            InternetAvailability = new subsystems.network.InternetAvailabilityTest();
            InternetAvailability.AvailabilityChanged += InternetAvailability_AvailabilityChanged;
            InternetAvailability.StartPeriodicTest();

        }

        private void InternetAvailability_AvailabilityChanged(object sender, subsystems.network.InternetAvailabilityTest.AvailabilityChangedEventArgs e)
        {
            // update INTERNET STATUS led
            Display.SetLedIndicators(LedLocations.Middle, e.AvailableNow ? LedColors.Dark : LedColors.Red);
        }

        private void _SystemMenuScreen_AppKeyPress(object sender, AppKeyPressEventArgs e)
        {
            // App key in System Menu: EXIT to current App 
            ScreenManager.Show(_AppManager.CurrentApp.ScreenMain);
            e.KeypressFeedbackBuzz = true;
            e.Handled = true;
        }

        // filter keyboard events
        private void _proxiedDisplay_KeypadPreviewEvent(object sender, ProxyKeypadEventPreviewArgs e)
        {
            if (e.Key == KeypadKeys.System)
            {
                // filter SYSTEM key press from application level
                e.Filter = true;

                // bring up system menu
                if (ScreenManager.CurrentScreen != _SystemMenuScreen)
                {
                    ScreenManager.Show(_SystemMenuScreen);
                    ScreenManager.Buzz();
                }
                else
                {
                    // app key pressed twice
                    // TODO: show soft power off screen
                }
            }
        }

        ~Director()
        {
            InternetAvailability.StopPeriodicTest();
            InternetAvailability = null;

            _AppManager.UnloadAll();
            _AppManager.Director = null;
            _AppManager = null;

            _SystemMenuScreen.AppKeyPress -= _SystemMenuScreen_AppKeyPress;
            _SystemMenuScreen = null;
            _SystemMenu = null;

            ScreenManager = null;
            Display.Reset();
            Display = null;

            _SerialPort.Close();
            _SerialPort = null;
        }
        #endregion

        #region Public Interface

        // the Display
        public IDisplay Display { private set; get; }

        // the Screen Manager
        public ScreenManager ScreenManager { private set; get; }

        // system menu item
        public MenuItem SystemMenu { get { return _SystemMenu; } }

        public ApplicationManager ApplicationManager { get { return _AppManager; } }

        //  Check if port available on Linux: File.Exists(s.PortName);
        public bool IsRunningOnMono { get { return (Type.GetType("Mono.Runtime") != null); } }

        public subsystems.network.InternetAvailabilityTest InternetAvailability { private set; get; }

        // initialize director and subsystems
        public void Initialize()
        {
           //ThreadPool.QueueUserWorkItem(new WaitCallback(CheckInetStatus));
            //cfgLoader.LoadConfigurator("test.conf");
            _AppManager.Load("StreamOne", "Tuner");
            _AppManager.Application("Stream One").Activate();
        }

        #endregion

        #region Private Methods

        private void TmrCheckInet_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
        {

        }

        public void UpdateInetStatus(bool isAvailable)
        {
            lock (Display.SyncLock)
            {
                Display.SetLedIndicators(LedLocations.Middle, isAvailable ? LedColors.Dark : LedColors.Red);
            }
        }
        #endregion

    }

}
